﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Diagnostics;
using SimpleIR;

namespace InterpreterCore
{
	/// <summary>
	/// This class represents a delegate object on the heap.
	/// </summary>
	internal sealed class CDelegate : CObject
	{
		/// <summary>
		/// The method that this delegate object is encapsulating.
		/// </summary>
		internal readonly IRInvokeIdentity m_invoke;

		private CDelegate(int address, IRLambdaType loctype, CompositeValueEntry[] contents, IRInvokeIdentity iiv) : 
			base(address, loctype, contents)
		{
			this.m_invoke = iiv;
		}

		internal static CDelegate InterpAllocateObject(int address, IRLambdaType loctype, IRInvokeIdentity iiv)
		{
			CompositeValueEntry[] cvv = CompositeValue.MakeCompositeValue(loctype);

			return new CDelegate(address, loctype, cvv, iiv);
		}

		public override string ToString()
		{ return String.Format("{0}:{1} with {2}", this.LocationType.BaseTypeName, CompositeValue.Stringify(this.m_objcontents), this.m_invoke.ToString()); }

		internal override string DebuggerString()
		{ return String.Format("{1} at {0} : {2}::{3}", this.Address, this.LocationType.BaseTypeName, this.m_invoke.DefInClass.BaseTypeName, this.m_invoke.InvSig.InvokeName); }

		internal override void SerializeForHeapDump(System.IO.TextWriter dumpstr)
		{
			string ohs = String.Format("LFlag=Dlgt LAddr={0} LType={1} LFunc={2} LValue=", this.Address, this.LocationType.TypeID, this.m_invoke.InvIDStableKey);
			dumpstr.Write(ohs);
			CompositeValue.SerializeForHeapDump(dumpstr, this.m_objcontents);
		}

		internal override void SerializeForDGMLDisplay(System.Xml.XmlWriter nodexw, System.Xml.XmlWriter edgexw, string lname)
		{
			nodexw.WriteStartElement("Node");
			nodexw.WriteAttributeString("Id", this.Address.ToString());
			nodexw.WriteAttributeString("Label", String.Format("{0} {1}::{2}", this.LocationType.BaseTypeName, this.m_invoke.DefInClass.BaseTypeName, this.m_invoke.InvSig.InvokeName));
			nodexw.WriteAttributeString("Background", "grey");
			nodexw.WriteEndElement();

			for(int i = 0; i < this.m_objcontents.Length; ++i)
			{
				if(this.m_objcontents[i].Offset.PathLast.FieldType is IRPtrType)
				{
					PtrValue pv = this.m_objcontents[i].Value.ConvertToPassablePtrValue();
					if(!pv.IsNullPtr)
					{
						edgexw.WriteStartElement("Link");
						edgexw.WriteAttributeString("Source", this.Address.ToString());
						edgexw.WriteAttributeString("Target", pv.TargetAddress.ToString());
						edgexw.WriteAttributeString("Label", this.m_objcontents[i].Offset.FieldOnlyDisplayString());
						edgexw.WriteEndElement();
					}
				}
			}
		}

		internal static CDelegate DelgateParseLocation(Dictionary<string, string> pkvp)
		{
			Debug.Assert(pkvp["LFlag"].Equals("Dlgt"));

			int addr = Int32.Parse(pkvp["LAddr"]);

			int typeid = Int32.Parse(pkvp["LType"]);
			IRLambdaType ltype = (IRLambdaType)GlobalInterpreterState.TProg.TypeTable.LookupTypeForID(typeid);

			CompositeValueEntry[] cve = CompositeValue.ParseValue(ltype, pkvp["LValue"]);

			int invid = Int32.Parse(pkvp["LFunc"]);
			IRInvokeIdentity iiv = GlobalInterpreterState.TProg.InvokeTable.GetInvokeWithID(invid);

			return new CDelegate(addr, ltype, cve, iiv);
		}

		public PtrValue LoadObjectArgPointer()
		{
			IRClassType delegatebase = (IRClassType)GlobalInterpreterState.TProg.TypeTable.LookupTypeForName("System.Delegate");
			IRMemberField tfield = delegatebase.TypeDescription.GetFieldWithNameDefIn("target");
			PtrValue tpv = this.ReadPassablePtrValueFromField(tfield);

			return tpv;
		}
	}
}
